#include "number.h"

void bounds_free (Bounds* bounds)
{
    if (bounds)
    {
        if (bounds->re_min)
        {
            mpfr_clear(bounds->re_min);
        }
        
        if (bounds->re_max)
        {
            mpfr_clear(bounds->re_max);
        }
        
        if (bounds->im_min)
        {
            mpfr_clear(bounds->im_min);
        }
        
        if (bounds->im_max)
        {
            mpfr_clear(bounds->im_max);
        }
        
        free(bounds);
        bounds = NULL;
    }
}

Bounds* bounds_new ()
{
    Bounds* bounds = malloc(sizeof(Bounds));
    
    if (bounds == NULL)
    {
        return NULL;
    }
    
    memset(bounds, 0, sizeof(Bounds));
    
    mpfr_init2(bounds->re_min, PREC);
    mpfr_init2(bounds->re_max, PREC);
    mpfr_init2(bounds->im_min, PREC);
    mpfr_init2(bounds->im_max, PREC);
    
    mpfr_set_inf(bounds->re_min, 1);
    mpfr_set_inf(bounds->re_max, -1);
    mpfr_set_inf(bounds->im_min, 1);
    mpfr_set_inf(bounds->im_max, -1);
    
    return bounds;
}

void bounds_update_re (Bounds* bounds, mpfr_t num, int re_closed, int exact)
{
    int min_cmp = mpfr_cmp(bounds->re_min, num);
    int max_cmp = mpfr_cmp(bounds->re_max, num);
    
    if (min_cmp != -1)
    {
        mpfr_set(bounds->re_min, num, MPFR_RNDN);
        bounds->re_min_closed = (min_cmp) ? re_closed : bounds->re_min_closed || re_closed;
    }
    
    if (max_cmp != 1)
    {
        mpfr_set(bounds->re_max, num, MPFR_RNDN);
        bounds->re_max_exact = exact;
        bounds->re_max_closed = (max_cmp) ? re_closed : bounds->re_max_closed || re_closed;
    }
}

void bounds_update_im (Bounds* bounds, mpfr_t num, int im_closed, int exact)
{
    int min_cmp = mpfr_cmp(bounds->im_min, num);
    int max_cmp = mpfr_cmp(bounds->im_max, num);
    
    if (min_cmp != -1)
    {
        mpfr_set(bounds->im_min, num, MPFR_RNDN);
        bounds->im_min_closed = (min_cmp) ? im_closed : bounds->im_min_closed || im_closed;
    }
    
    if (max_cmp != 1)
    {
        mpfr_set(bounds->im_max, num, MPFR_RNDN);
        bounds->im_max_exact = exact;
        bounds->im_max_closed = (max_cmp) ? im_closed : bounds->im_max_closed || im_closed;
    }
}

void bounds_update (Bounds* bounds, mpc_t num, int re_closed, int im_closed, int mpc_inex)
{
    mpfr_t re;
    mpfr_t im;
    
    mpfr_init2(re, PREC);
    mpfr_init2(im, PREC);
    
    mpc_real(re, num, MPFR_RNDN);
    mpc_imag(im, num, MPFR_RNDN);
    
    bounds_update_re(bounds, re, re_closed, MPC_INEX_RE(mpc_inex) == 0);
    bounds_update_im(bounds, im, im_closed, MPC_INEX_IM(mpc_inex) == 0);
    
    mpfr_clear(re);
    mpfr_clear(im);
}
